﻿/**************************************************************************************
 * RecordManagement.cs
 * An utility class to declare/undeclare documents as records and move them back and 
 * fort between a Record Center Site and its original
 * location
 * Jaime Alberto Jaramillo Zapata (jjaramillo.informatica-tecnologia.com)
 * Created on 02/02/2012.
 * Last update on 03/02/2012.
 **************************************************************************************/

using System;
using System.Linq;
using Microsoft.SharePoint;
using Microsoft.Office.RecordsManagement.RecordsRepository;

namespace MS.InformationManagement.Support
{
    /// <summary>
    /// An utility class to declare/undeclare documents as records and move them back and fort between a Record Center Site and its original
    /// location.
    /// </summary>
    public class RecordManagement
    {
        /// <summary>
        /// Sends the document to record store.
        /// </summary>
        /// <param name="fileUrl">The file URL.</param>
        /// <param name="recordCenterName">Name of the record center.</param>
        /// <param name="web">The Sharepoint foundation website.</param>
        /// <returns></returns>
        public static string SendDocumentToRecordStore(string fileUrl, string recordCenterName, SPWeb web)
        {
            string recordUrl = string.Empty;
            try
            {
                string additionalInformation = string.Empty;
                SPOfficialFileHost targetFileHost = null;
                SPFile targetFile = null;
                string[] recordOperationDetails;

                targetFileHost = web.Site.WebApplication.OfficialFileHosts.SingleOrDefault(rc => rc.OfficialFileName.Equals(recordCenterName));
                if (targetFileHost == null) { throw new Exception("Send Connection not found"); }

                targetFile = web.GetFile(fileUrl);

                Microsoft.SharePoint.OfficialFileResult sentResult = targetFile.SendToOfficialFile(targetFile.Item.ContentType.Name, targetFileHost, web.CurrentUser.Email,
                        SPOfficialFileSubmissionMode.Manual, out additionalInformation);

                switch (sentResult)
                {
                    case Microsoft.SharePoint.OfficialFileResult.Success:
                        recordUrl = additionalInformation.GetRecordUrl();
                        break;
                    case Microsoft.SharePoint.OfficialFileResult.FileCheckedOut:
                        //The target document is currently checked out.
                        throw new Exception("Failed to move the document to the Record Center. The target document is currently checked out. Check it in and try again.");
                        break;
                    case Microsoft.SharePoint.OfficialFileResult.FileDeleteAccessDenied:
                        //The current user does not have access to the specified document
                        throw new Exception("Failed to move the document to the Record Center. The current does not has access to the document.");
                        break;
                    case Microsoft.SharePoint.OfficialFileResult.FileExists:
                        //The record already exists at the target record store location
                        throw new Exception("Failed to move the document to the Record Center. The record already exists in the Record Center location.");
                        break;
                    case Microsoft.SharePoint.OfficialFileResult.FileRejected:
                        //Could not complete the file transfer due to file size overflow
                        throw new Exception("Failed to move the document to the Record Center. The document exceeds the maximum file size allowed.");
                        break;
                    case Microsoft.SharePoint.OfficialFileResult.InvalidUser:
                        //Could not complete the file transfer due to the current user being invalid.
                        throw new Exception("Failed to move the document to the Record Center. The current user is invalid.");
                        break;
                    case Microsoft.SharePoint.OfficialFileResult.MoreInformation:
                        //Could not complete the file transfer due to the document being checked out by another user.
                        throw new Exception("Failed to move the document to the Record Center. The target document is checked out by another user.");
                        break;
                    case Microsoft.SharePoint.OfficialFileResult.NotFound:
                        //Could not complete the file transfer. The file does not exists.
                        throw new Exception("Failed to move the document to the Record Center. The target record center does not exist or is innaccessible");
                        break;
                    case Microsoft.SharePoint.OfficialFileResult.ReplaceLinkFailed:
                    //Could not complete the file transfer due to some exception. Check the additional information string for more info.
                    case Microsoft.SharePoint.OfficialFileResult.InvalidRouterConfiguration:
                    //Could not complete the file file transfer due to some the content organizer not being configured correctly, or not being 
                    //configured at all.
                    case Microsoft.SharePoint.OfficialFileResult.InvalidConfiguration:
                    //Could not complete the file transfer due to some unknown exception. Check the additional information string for more
                    //info.
                    case Microsoft.SharePoint.OfficialFileResult.InvalidArgument:
                    //Could not complete the file transfer due to some invalid argument exception. Check the additional information string for
                    //more info
                    case Microsoft.SharePoint.OfficialFileResult.UnknownError:
                    //Could not transfer the file due to some unknown error. Check the additional information string for more info.
                    case Microsoft.SharePoint.OfficialFileResult.FileMoveFailed:
                        //Could not complete the document transfer due to some exception. Check the additional information string for more info
                        recordOperationDetails = additionalInformation.GetRecordUrlAndErrorDetails();
                        throw new Exception(string.Format("Failed to move the document to the Record Center at {0}, due to {1}.", recordOperationDetails[0], recordOperationDetails[1]));
                        break;
                    case Microsoft.SharePoint.OfficialFileResult.RepositoryNotFound:
                        //Could not transfer the file. The submission location was not found.
                        throw new Exception("Failed to move the document to the Record Center. The submission location was not found.");
                        break;
                }

            }
            catch (Exception ex)
            {
                //TODO: Manage exception
                throw;
            }
            return recordUrl;
        }

        /// <summary>
        /// Sends the record to document library.
        /// </summary>
        /// <param name="recordUrl">The url of the record to be undeclared.</param>
        /// <param name="web">The Sharepoint foundation record center website.</param>
        /// <param name="targetSiteUrl">The target site URL where the document is going to be restored.</param>
        /// <param name="libraryPath">The library path where the document is going to be restored.</param>
        /// <param name="folderPath">The folder stucture inside the document library where the document is going to be restored.</param>
        /// <returns>
        /// The restored document's absolute url.
        /// </returns>
        public static string SendRecordToDocumentLibrary(string recordUrl, SPWeb web, string targetSiteUrl, string libraryPath, string folderStructure, bool overwrite)
        {

            string documentPath = string.Empty;

            SPListItem itemToUndeclare = web.GetListItem(string.Format("{0}/{1}", web.Url, recordUrl));

            /*
             * Check if the record to restore has a file. 
             */
            if (itemToUndeclare.File == null) { throw new Exception("The item you're trying to undeclare does not have an associated document."); }

            using (SPSite targetSite = new SPSite(targetSiteUrl))
            {
                using (SPWeb targetWeb = targetSite.OpenWeb())
                {
                    SPDocumentLibrary targetLibrary = targetWeb.GetList(string.Format("{0}/{1}", targetWeb.Url, libraryPath)) as SPDocumentLibrary;

                    if (targetLibrary != null)
                    {

                        SPFolder currentSPFolder = targetLibrary.RootFolder;

                        /*
                         * If there is a folder structure check if it exists, and if not create it recursively
                         */
                        if (!string.IsNullOrEmpty(folderStructure))
                        {
                            string[] folders = folderStructure.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                            string fullCurrentFolderPath = string.Format("{0}/{1}", targetWeb.Url, libraryPath);
                            string currentFolderPath = string.Empty;

                            foreach (string currentFolder in folders)
                            {
                                fullCurrentFolderPath = string.Format("{0}/{1}", fullCurrentFolderPath, currentFolder);
                                currentFolderPath = string.Format("{0}/{1}", currentFolderPath, currentFolder);
                                SPFolder targetFolder = targetWeb.GetFolder(fullCurrentFolderPath);

                                if (!targetFolder.Exists)
                                {
                                    currentSPFolder = currentSPFolder.SubFolders.Add(currentFolder);
                                }
                                else
                                {
                                    currentSPFolder = targetFolder;
                                }
                            }
                        }
                        /*
                         * If there's no folder structure, just grab the target library's root folder
                         */
                        else
                        {
                            currentSPFolder = targetLibrary.RootFolder;
                        }

                        Records.UndeclareItemAsRecord(itemToUndeclare);

                        /*
                         * Finally add a file with the same metadata from the record store to the folder structure on the target library and delete the record. 
                         */
                        documentPath = string.Format("{0}/{1}",
                                            targetSiteUrl,
                                            currentSPFolder.Files.Add(itemToUndeclare.File.Name,
                                                itemToUndeclare.File.OpenBinary(),
                                                itemToUndeclare.Properties, overwrite)
                                        );
                        itemToUndeclare.Delete();
                    }
                }
            }
            return documentPath;
        }
    }
}
